第二章 CSS 工作原理
发表于 2017-12-26 11:21:37 | 分类于 CSS |
剖析 CSS 规则
规则是一条完整的CSS 指令。规则声明了要修改的元素和要应用给该元素 的样式。
p {color:red;}
为文档添加样式的三种方法
- 行内样式:写在元素标签里
- 嵌入样式:写在
<style>
标签里 - 链接样式:写在单独的CSS 样式表中
行内样式
行内样式的作用范围非常有限。行内样式只能影响它所在的标签,而且总会覆盖嵌入样式和链接样式。
嵌入样式
嵌入的CSS 样式放在HTML 文档的 <head>
元素。嵌入样式的应用范围仅限于当前页面。页面样式会覆盖外部样式表中的样式,但会被行内样式覆盖。
链接样式
在创建包含多个页面的网站时,需要把样式集中在一个单独的文件里,这个文件就叫样式表。
样式表是一个扩展名为.css 的文本文件。可以在任意多个HTML 页面中链接同一个样式表文件。
每个页面中只需加入类似下面的这一行代码即可:
<link href="styles.css" rel="stylesheet" type="text/css" />
链接样式的作用范围可以是整个网站。
只要使用 <link>
标签把样式表链接到每个页面,相应的页面就可以使用其中的样式。随后,只要修改了样式表中的样式,改动就会在所有被选中的元素上体现出来,无论这个元素在哪个页面里。这样,既可以做到全站页面外观统一,又便于整站样式更新。
@import
指令
除了以上三种为页面添加样式的方法,还有一种在样式表中链接其他样式表的方法,那就应用 @import
指令(是一种 at 规则):
@import url(css/styles2.css)
要注意的是,@import
指令必须出现在样式表中其他样式之前,否则@import 引用的样式表不会被加载。
注意
CSS 样式是通过 <style>
标签嵌入到页面里的。当浏览器遇到开标签 <style>
时,就会由解释 HTML 代码切换为解释 CSS 代码。等遇到闭标签
</style>
时,它会再切换回解释 HTML 代码。
对于写在样式表里的样式,就不需要 <style>
标签了。如果在样式表里加上这个标签,样式表中的样式就不会被浏览器加载了。
CSS 规则命名惯例
CSS 规则由选择符和声明两部分组成。
选择符用于指出规则所要选择的元素。
声明由两部分组成:属性和值。属性指出要影响元素哪方面的样式,值就是属性的一个新状态。
上下文选择符
上下文选择符,基于祖先或同胞元素选择一个元素。 CSS 规范里,叫后代组合式选择符,就是一组以空格分隔的标签名。用于选择作为指定祖先元素后代的标签。
格式: 标签1 标签2 {声明}
标签 2 是想要选择目标,而且只有在标签 1 是其祖先元素(不一定是 父元素)的情况下才会被选中。
特殊的上下文选择符
子选择符
格式: 标签 1 > 标签 2 {声明}
标签 2 必须是标签 1 的子元素,或者说,标签 1 必须是标签 2 的父元素。与常规的上下文选择符不同,这个选择符中的标签 1 不能是标签 2 的父元素之外的其他祖先元素。
紧邻同胞选择符
格式:标签 1 + 标签 2 {声明}
标签 2 必须紧跟在其同胞标签 1 的后面。
一般同胞选择符
格式:标签 1 ~ 标签 2 {声明}
标签 2必须跟(不一定紧跟)在其同胞标签 1 后面。
通用选择符 *
格式: * {声明}
通用选择符 *
(常被称为星号选择符)是一个通配符,它匹配任何元素。
ID 和类选择符
ID 和类为选择元素提供了另一套手段,利用它们可以不用考虑文档的层次结构。
可以给id 和class 属性设定任何值,但不能以数字或特殊符号开头。
类属性
类属性是 HTML 元素的 class 属性,body 标签中包含的任何 HTML 元素都可以添加这个属性。
类选择符
格式: .类名
类选择符就是在 HTML 类名前面加一个点(英文句号)。点(.)、 类名之间没有空格。
标签带类选择符
如果只想瞄准带有这个类的段落,可以把标签名和类选择符写在一块,比如:
p.specialtext {...}
该规则只选择带 specialtext 类的段落。
多类选择符
可以给元素添加多个类,比如:
<p class="specialtext featured">Here the span tag <span>may or may not</span> be styled.</p>
HTML 的 class 属性可以有多个空格分隔的值。
选择同时存在这两个类名的元素:
.specialtext.featured {...}
CSS 选择符的两个类名之间没有空格,因为只想选择同时具有这两个类 名的那个元素。如果加了空格,那就变成了“祖先/后代”关系的上下文选择符了。
每个类名分别用一个 HTML class 属性的做法是常见的错误,正确的做法是像上面的代码那样,只用一个class 属性,但给它设定多个值。
ID 属性
ID 与类的写法相似,表示 ID 选择符的 #
的用法,也跟表示类选择符的 .
类似。
如果有一个段落像下面这样设定了 ID 属性:
<p id="specialtext">This is the special text.</p>
那么,相应的 ID 选择符就是这样的:
#specialtext {...}
或者这样的:
p#specialtext {...}
除此之外,ID 与类的用法都一样,而且前面关于类选择符的(几乎)一 切,都适应于 ID 选择符。
用于页内导航的 ID
ID 也可以用在页内导航链接中。 下面就是一个链接,其目标是同一页的另一个位置:
<a href="#bio">Biography</a>
href 属性值开头的 #, 它表示这个链接的目标在当前页面中,因而不会触发浏览器加载页面(如果没有#,浏览器就会尝试加载 bio 目录下的默认页面了)。
使用与 CSS 选择符里相同的 #ID 名语法,可以把链接导航到同一页面中的目标ID。在这个页面的下方,应该有对应的目标元素:
<h3 id="bio">Biography</h3>
<p>I was born when I was very young…</p>
注意,作为目标的 ID 值前面是没有 #
的,就是一个普通的 ID 值。
用户单击前面的链接时,页面会向下滚动到 ID 值为 bio 的 h3 元素的位置。
如果链接的 href 属性里只有一个 #
,那么点击该链接会返回页面顶部: <a href="#">Back to Top</a>
要写一个“返回顶部”链接,不需要 ID 为 #
的目标元素。
如果暂时不知道某个 href 应该放什么 URL,也可以用 #
作为占位符,但不能把该属性留空。因为 href 属性值为空的链接的行为跟正常链接不一样。这样,团队中的其他人将来可以用中间层(比如PHP)变量替换 #
,以便动态接收来自数据库的 URL。
什么时候用 ID,什么时候用类
什么时候用 ID
ID 的用途是在页面中唯一地标识一个元素。因此,同一个页面中的每一个 ID 属性,都必须有独一无二的值(名字)。换一个角度讲,每个ID 名在页面中都只能用一次。
也可以使用 ID 把 JavaScript 与某个标签关联起来(比如,当用户鼠标移动到一个链接上面时,运行激活动画的脚本)。ID 值的唯一性对 JavaScript 尤其重要,否则就会导致 JavaScript 行为异常。
<nav id="mainmenu">
在这里,页面中就不能再有其他元素使用 mainmenu 作为 ID 名了。为了标识页面的某一部分,比如主导航菜单,可以为 nav(navigation,导航)添加一个 ID 属性,并让它包含菜单元素。
<nav id="mainmenu">
<ul>
<li><a href="#">Yin</a></li>
<li><a href="#">Yang</a></li>
</ul>
</nav>
有了用唯一 ID 标识的菜单之后,就可以使用上下文选择符来选择其中包含的各种类型的标签了。
比如,可以将这个菜单中的链接设置为橙色,同时又不会影响页面中 的其他链接:
#mainmenu a {color:orange;}
利用唯一 ID,可以在 CSS 中方便地定位到这个元素,以及它的子元素。可以给页面中每个顶级区域都添加一个 ID,从而得到非常明确的上下文,以便编写 CSS 时只选择嵌套在相应区域内的标签。
什么时候使用类
类的目的是为了标识一组具有相同特征的元素。
在下面这个孩子名字的列表中,要把男孩的名字变成蓝色,把女孩的名字变成粉红色。首先,用类在标记中标识出了性别。
<nav>
<ul>
<li class="boy"><a href="#">Alan</a></li>
<li class="boy"><a href="#">Andrew</a></li>
<li class="girl"><a href="#">Angela</a></li>
<li class="boy"><a href="#">Angus</a></li>
<li class="girl"><a href="#">Anne</a></li>
<li class="girl"><a href="#">Annette</a></li>
</ul>
</nav>
然后,再用CSS 为链接应用颜色:
.boy a {color:#6CF;} /*蓝色*/
.girl a {color:#F9C;} /*粉红色*/
第一条规则选择所有类名为 boy 的祖先元素包含的 a 元素,第二条规则选择所有类名为 girl 的祖先元素包含的 a 元素。这两种情况下的祖先元素,都是作为相应链接父元素的 li 元素。
不要乱用类
不要像使用 ID 一样,每个类都指定一个不同的类名,然后再为每个类编写规则。
如果你确实有这种随意使用类的习惯,说明还不了解继承和上下文选择符的作用。于是,可能会给每个标签都重复写同样的样式(比如为页面中很多标签分别指定相同的字体)。实际上,继承和上下文选择符能让不同的标签共享样式,从而降低需要编写和维护的 CSS 量。
ID 和 类的小结
ID 的用途是在页面标记中唯一地标识一个特定的元素。它能够为编写CSS 规则提供必要的上下文,排除无关的标记,而只选择该上下文中的标签。
类是可以应用给任意多个页面中的任意多个HTML 元素的公共标识符, 以便为这些元素应用相同的CSS 样式。而且,使用类也让为不同标签名的元素应用相同的样式成为可能。
属性选择符
它基于HTML 标签的属性选择元素。
属性名选择符
格式:标签名[属性名] {...}
选择任何带有属性名的标签名。
示例:
/* 选择带有title 属性的 HTML img 元素 */
img[title] {...}
属性值选择符
格式:标签名[属性名="属性值"]{...}
在 HTML5 中,属性值的引号可加可不加。
选择任何带有值为属性值的属性名的标签名。
示例:
/* 选择 title 属性值为 "red flower" 的 HTML img 元素 */
img[title="red flower"] {...}
更多的属性选择符形式
属性选择符小结
基于属性名和属性的其他特征选择元素,提供了另一种区别对待相同标签的 机会。
伪类
到现在为止,介绍的选择符都有一个共同点,即它们针对的都是标记中的某个部分,比如标签名、类名、ID、属性或属性值。
然而,使用CSS 还可以在某些事件发生时,改变某些元素的样式,比如用户鼠标悬停在一个链接上。而这就要靠伪类来实现。
伪类分两种:
- UI(User Interface,用户界面)伪类,会在 HTML 元素处于某个状态时(比如鼠标指针位于链接上),为该元素应用 CSS 样式。
- 结构化伪类,会在标记中存在某种结构上的关系时(如某个元素是一组元素中的第一个或最后一个),为相应元素应用 CSS 样式。
UI 伪类
UI 伪类会基于特定 HTML 元素的状态应用样式。
链接伪类
针对链接的伪类一共有 4 个,因为链接始终会处于如下 4 种状态之一:
- Link。此时,链接就在那儿等着用户点击。
- Visited。用户此前点击过这个链接。
- Hover。鼠标指针正悬停在链接上。
- Active。链接正在被点击(鼠标在元素上按下,还没有释放)。
以下是这些状态对应的 4 个伪类选择符:
a:link {...}
a:visited {...}
a:hover {...}
a:active {...}
/* 由于这4 个伪类的特指度相同,如果不按照这里列出的顺序使用它们,浏览器可能不会显示预期结果。 */
一个冒号(:)表示伪类,两个冒号(::)表示 CSS3 新增的伪元素。浏览器目前都支持对 CSS 1 和 CSS 2 的伪元素使用一个冒号,但希望能习惯于用双冒号代替单冒号,因为这些单冒号的伪元素最终可能都会被淘汰掉
注意,有些伪类可以用于任何元素,而不仅仅是 a 元素。
:focus 伪类
格式:e:focus
e 表示任何元素,如p、h1、section,等等。
:target 伪类
格式:e:target
如果用户点击一个指向页面中其他元素的链接,则那个元素就是目标(target),可以用 `:target 伪类选中它。
示例:
<a href="#more_info">More Information</a>
<!-- 位于页面其他地方、ID 为 more_info 的那个元素就是目标。-->
<h2 id="more_info">This is the information you are looking for.</h2>
那么,
#more_info:target {background:#eee;}
会在用户单击链接转向 ID 为 more_info 的元素时,为该元素添加浅灰色背景。
结构化伪类
结构化伪类可以根据标记的结构应用样式。
:first-child 和 :last-child
格式:
e:first-child
e:last-child
:first-child
代表一组同胞元素中的第一个元素,而 :last-child
则代表最后一个。
示例:
<ol class="results">
<li>My Fast Pony</li>
<li>Steady Trotter</li>
<li>Slow Ol' Nag</li>
</ol>
ol.results li:first-child {color:blue;}
文本 “My Fast Pony” 就会变成蓝色。
如果选择符改成这样:
ol.results li:last-child {color:red;}
那变成红色的文本就是 “Slow Ol’ Nag” 了
补充
- 只要 E 元素是它的父级的第一个子元素,就选中。它需要同时满足两个条件,一个是“第一个子元素”,另一个是“这个子元素刚好是 E ”。
- 类似容易误解的结构选择器还有: nth-child()、:nth-last-child、:only-child
:nth-child
格式:
e:nth-child(n)
e 表示元素名,n 表示一个数值(也可以使用 odd 或 even)。
示例:
li:nth-child(3)
会选择一组列表项中的每个第三项。
更多的 伪类
伪元素
伪元素是文档中若有实无的元素。
::first-letter 伪元素
格式:
e::first-letter
选中一整块文字第一行的第一个字母,并且文字所处的行之前没有其他内容(如图片和内联的表格) 。
::first-line 伪元素
格式:
e::first-line
选中文本段落(一般情况下是段落)的第一行。
::before 和 ::after 伪元素
格式:
e::before
e::after
可用于在特定元素前面或后面添加特殊内容。
注意 搜索引擎不会取得伪元素的信息(因为它在标记中并不存在)。因此,不要通过伪元素添加你想让搜索引擎索引的重要内容。
更多关于伪类的内容:
https://developer.mozilla.org/zh-CN/docs/Web/CSS/::first-letter
https://developer.mozilla.org/zh-CN/docs/Web/CSS/Pseudo-classes
https://developer.mozilla.org/zh-CN/docs/Learn/CSS/Introduction_to_CSS/Pseudo-classes_and_pseudo-elements
继承
CSS 中的祖先元素也会向后代传递一样东西:CSS 属性的值。
CSS 中有很多属性是可以继承的,其中相当一部分都跟文本有关,比如颜色、字体、字号。
也有很多CSS 属性不能继承,因为继承这些属性没有意义。这些不能 继承的属性主要涉及元素盒子的定位和显示方式,比如边框、外边距、内边距。
由于字体和文本样式是可以继承的,所以在使用相对字体单位(如百分比和 em )时要格外小心。如果某个标签的字体大小被设置为80%,而它的一个后代的字体大小也被设置为 80%,那么该后代中文本最终的字体大小将是 64%( 80% 的 80% )。
可以参考 CSS参考资料, 每个单独的属性页都会从一个汇总表开始,其中包含有关该元素的各种详细信息,包括是否被继承。
层叠
层叠,是一种样式在文档层次中逐层叠加的过程,目的是让浏览器面对某个标签特定属性值的多个来源,确定最终使用哪个值。
样式来源
浏览器层叠各个来源样式的顺序:
- 浏览器默认样式表
- 用户样式表
- 作者链接样式表(按照它们链接到页面的先后顺序)
- 作者嵌入样式
- 作者行内样式
浏览器会按照上述顺序依次检查每个来源的样式,并在有定义的情况下,更新对每个标签属性值的设定。整个检查更新过程结束后,再将每个标签以最终设定的样式显示出来。
层叠规则
层叠规则一:找到应用给每个元素和属性的所有声明
浏览器在加载每个页面时,都会据此查到每一条CSS 规则,标识出所有受到影响的HTML 元素。
层叠规则二:按照顺序和权重排序。浏览器依次检查 5 个来源,并设定匹配的属性
如果匹配的属性在下一个来源也有定义,则更新该属性的值,如此循环,直到检查完页面中所有标签受影响属性的全部 5 个来源为止。最终某个属性被设定成什么值,就用什么值来显示。
声明也可以有权重。可以像下面这样为单独的声明增加权重:
p {color:green !important; font-size:12pt;}
空格 !important 分号(;)用于加重声明的权重。
这条规则加重了将文本设置为绿色的权重。就算层叠的下一来源给段落设定了其他颜色,最终的颜色值仍然还是绿色。说到底,就是一种特权。
层叠规则三:按特指度排序。
特指度表示一条规则有多明确。一条规则的特指度,由它的选择符中包含多少个标签、类名和 ID 决定。
计算特指度
记分规则:对每个选择符都要按下面的 “I-C-E” 公式计算三个值。
三个字母间的短横线是分隔符,并非减号。针对这个公式的计分办法如下:
- 选择符中有一个 ID,就在 I 的位置上加 1;
- 选择符中有一个类,就在 C 的位置上加 1;
- 选择符中有一个元素(标签)名,就在 E 的位置上加 1;
- 得到一个三位数。
示例:
选择符 | I-C-E | 特指度 |
---|---|---|
P | 0-0-1 | 1 |
p.largetext | 0-1-1 | 11 |
p#largetext | 1-0-1 | 101 |
body p#largetext | 1-0-2 | 102 |
body p#largetext ul.mylist | 1-1-3 | 113 |
body p#largetext ul.mylist lit | 1-1-4 | 114 |
在此,每个选择符都比前一个选择符的特指度更高。
层叠规则四:顺序决定权重
如果两条规则都影响某元素的同一个属性,而且它们的特指度也相同,则位置最靠下(或后声明)的规则胜出。
层叠要点
-
规则一:包含 ID 的选择符胜过包含类的选择符,包含类的选择符胜过包含标签名的选择符。
-
规则二:如果几个不同来源都为同一个标签的同一个属性定义了样式,行内样式胜过嵌入样式,嵌入样式胜过链接样式。在链接的样式表中,具有相同特指度的样式,后声明的胜过先声明的。
-
规则一胜过规则二。换句话说,如果选择符更明确(特指度更高),无论它在哪里,都会胜出。(存在疑问:内联样式应该比 ID 更高)
-
规则三:设定的样式胜过继承的样式,此时不用考虑特指度(即显式设定优先)。
下面简单解释一下规则三。比如下面的标记:
<div id="cascade_demo">
<p id="inheritance_fact">Inheritance is <em>weak</em> in the Cascade</p>
</div>
和下面的规则:
div#cascade_demo p#inheritance_fact {color:blue;}
/* 2 - 0 - 2 (高特指度) */
会导致单词 “weak” 变成蓝色,因为它从父元素 p 那里继承了这个颜色值。但是,只要再给 em 添加一条规则:
em {color:red;}
/* 0 - 0 - 1 (低特指度) */
em 就会变成红色。因为,虽然它的特指度低(0-0-1),但 em 继承的颜色值,会被为它明确(显式)指定的颜色值覆盖,就算(隐式)遗传该颜色值的规则的特指度高(2-0-2)也没有用。
规则声明
一个声明包含两部分:属性和值。属性指出要影响元素的哪个方面(颜色、高度,等等),而值表示把属性设定为什么(绿色、12px,等等)。
每个元素都有很多属性,每个元素都有很多属性。
CSS 属性值主要分以下三类:
- 文本值。
- 例如,font-weight:bold 声明中的 bold 就一个文本值。文本值也叫做关键字。
- 数字值。
- 数字值后面都有一个单位,例如英寸或点。
- 在声明 font-size:12px 中,12 是数字值,而 px 是单位(像素)。如果数字值为 0,那么就不用带单位了。
- 颜色值。
- 颜色值可以用几种不同的格式来写,包括RGB(Red, Green, Blue,红绿蓝)、HSL(Hue, Saturation, Luminance,色相,饱和度,亮度)和十六进制值(例如 color:#336699)。
文本值
所有CSS 属性都有文本值
数字值
数字值主要分两类:绝对值和相对值。
绝对值描述的是一个真实的长度(比如,6 英寸),而相对值 则是相对于其他基准的描述(比如“是某某的两倍长”)。
绝对值及示例
绝 对 值 | 单位缩写 | 示 例 |
---|---|---|
英寸 | in | height: 6in |
厘米 | cm | height: 40cm |
毫米 | mm | height: 500mm |
点 | pt | height: 60pt |
皮卡 | pc | height: 90pc |
像素 | px | height: 72px |
打印纸是以英寸为单位度量的。
相对值及示例
相 对 值 | 单位缩写 | 示 例 |
---|---|---|
Em | em | height:1.2em |
Ex | ex | height:6ex |
百分比 | % | height:120% |
em 和 ex 都是字体大小的单位,但在CSS 中,它们作为长度单位适用于任何元素。
em ,它表示一种字体中字母 M 的宽度,因此它的具体大小取决于你使用的字体。
ex ,等于给定字体中字母 x 的高度(小写字母 x 代表一种字体的字母中间部分的高度,不包括字母上、下突出的部分——如 d 和 p 上下都出头儿)。
百分比非常适合设定被包含元素的宽度,此时的百分比就是相对于宽度而言的。
颜色值
颜色名
设定颜色属性时可以直接使用颜色关键字。
W3C 定义了 16 个颜色关键字:
颜色关键字 | ||
---|---|---|
aqua(浅绿色) | black(黑色) | blue(蓝色) |
fuchsia(紫红色) | gray(灰色) | green(绿色) |
lime(黄绿色) | maroon(褐红色) | navy(深蓝色) |
olive(茶青色 ) | purple(紫色) | red(红色) |
silver(银色) | teal(青色) | white(白色) |
yellow(黄色) |
要了解这些颜色名及其对应的 RGB 颜色值,可以参 考:http://www.w3.org/TR/css3-color/#html4。
十六进制颜色(#RRGGBB 或 #RGB)
格式:
#rrggbb
示例:
/* 橙色 */
#ff8800
这个 6 位数的前两位定义红色,中间两位定义绿色,后两位定义蓝色。
RGB 颜色值(R, G , B)
每种颜色都可以用一个 0 到 255(包含)之间的值指定。
格式如下:
rgb(r, g, b)
示例:
rgb(0,255,0)
表示纯绿色。
RGB 百分比值(R%, G%, B%)
这是用百分比来表示每种颜色值的一种方法。 格式:
r%, g%, b%
可以接受的值是 0% 到 100% 。这种方法只能表示区区一百万(100 × 100 × 100)种颜色。
使用百分比表示的颜色值,比使用十六进制更容易猜到你想要的颜色。举个例子,100%, 0%, 0% 是纯红色,0%, 100%, 0%是 纯绿色。
HSL (色相 , 饱和度 %, 亮度 %)
格式:
HSL(0,0%,0%)
HSL 颜色中的第一个值表示色相,也就是一个实际的颜色,比如红色和绿色。所有颜色围绕色相环(也叫色轮)一周,而色相值以圆周上的度数表示。
饱和度设定有多少颜色。<br> 灰色的饱和度低,而强烈的色彩饱和度高。
亮度设定颜色的明暗。<br> 0% 就是黑色,100% 就是白色,而中间的值是实际能看到的色相。
HSL 只有一个表示颜色的值。把饱和度和亮度都设定为 50%,就可以调制出 想要的任何颜色来。
Alpha 通道
RGB 和 HSL 都支持 Alpha 通道,用于设置颜色的不透明度(换句话说,就是能够透过多少背景)。<br> 相应的格式分别叫 RGBA 和 HSLA。其中,两种格式中的 A (alpha)值可以是 1(完全不透明)也可以是 0(完全透明),或者介于1 和 0 之间的小数值。